package com.tsmti.activiti.service.impl;

import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.tsmti.activiti.dao.ActExtendDao;
import com.tsmti.activiti.entity.ExtendActModel;
import com.tsmti.activiti.service.ActModelerService;
import com.tsmti.activiti.service.ExtendActModelerService;
import com.tsmti.core.common.constant.Constants;
import com.tsmti.core.common.query.data.Page;
import com.tsmti.core.common.query.data.PageImpl;
import com.tsmti.core.common.query.data.Pageable;
import com.tsmti.core.common.service.impl.BaseServiceImpl;
import com.tsmti.core.exception.MyException;
import com.tsmti.core.util.StringUtils;
import org.activiti.bpmn.converter.BpmnXMLConverter;
import org.activiti.bpmn.model.BpmnModel;
import org.activiti.bpmn.model.Process;
import org.activiti.editor.constants.ModelDataJsonConstants;
import org.activiti.editor.language.json.converter.BpmnJsonConverter;
import org.activiti.engine.ProcessEngine;
import org.activiti.engine.ProcessEngines;
import org.activiti.engine.RepositoryService;
import org.activiti.engine.repository.Deployment;
import org.activiti.engine.repository.Model;
import org.activiti.engine.repository.ProcessDefinition;
import org.hibernate.criterion.DetachedCriteria;
import org.hibernate.criterion.Restrictions;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.io.IOException;
import java.util.Arrays;
import java.util.List;

/**
 * @Package：com.tsmti.activiti.service.impl
 * @Class：ExtendActModelServiceImpl
 * @Description： TODO
 * @Author：zcw
 * @Date：Created in 2018/8/16 11:07
 * @Company:
 * @Version：
 * @Modified By:
 *
 */
@Service(value = "extendActModelService")
@Transactional(rollbackFor = Exception.class)
public class ExtendActModelServiceImpl extends BaseServiceImpl<ExtendActModel> implements ExtendActModelerService {

	@Autowired
	private RepositoryService repositoryService;

	@Autowired
	private ObjectMapper objectMapper;
	@Autowired
	private ActModelerService actModelerService;
	@Autowired
	private ActExtendDao actExtendDao;

	@Override
    @Transactional(rollbackFor = Exception.class)
	public void delete(String id){
        ExtendActModel actmodel = get(id, ExtendActModel.class);
        Model model = repositoryService.getModel(actmodel.getModelId());
        if(!StringUtils.isEmpty(model.getDeploymentId())){
            //删除部署表
            repositoryService.deleteDeployment(model.getDeploymentId());
        }
        //删除模型表
        repositoryService.deleteModel(model.getId());
        removeById(id);
	}
	
	@Override
	public void deleteBatch(String[] ids){
		removeAllById(Arrays.asList(ids));
	}

	@Override
	public ExtendActModel createModel(ExtendActModel extendActModel) {
		try {
			return actModelerService.createModeler(extendActModel);
		}catch (Exception e){
			logger.error("保存失败",e);
		}
		return new ExtendActModel();
	}

	@Override
	public Page<ExtendActModel> findPage(Pageable pageable, DetachedCriteria detachedCriteria) {
		Long total = count(detachedCriteria);
		List<ExtendActModel> content = list(pageable.getPageNumber(), pageable.getPageSize(), detachedCriteria);
		return new PageImpl<ExtendActModel>(content, pageable, total);
	}

	@Override
	public ExtendActModel findByWrokflowId(String workflowId) {
		DetachedCriteria detachedCriteria = DetachedCriteria.forClass(ExtendActModel.class);
		detachedCriteria.add(Restrictions.eq("workflowId",workflowId));
		List<ExtendActModel> actModelList = list(detachedCriteria);
		if(actModelList != null && actModelList.size() >0){
			return actModelList.get(0);
		}
		return null;
	}

	@Override
    @Transactional(rollbackFor = IOException.class)
	public void deploy(String modelId) throws IOException {
		if(StringUtils.isEmpty(modelId)){
			throw new MyException("流程模型id不能为空!");
		}
		Model model = repositoryService.getModel(modelId);
		//读取editorSource
		JsonNode jsonNode = objectMapper.readTree(repositoryService.getModelEditorSource(modelId));
		//转换editorSource为bpmnModel
		BpmnModel bpmnModel = new BpmnJsonConverter().convertToBpmnModel(jsonNode);
		//获取流程名称
		List<Process> processes = bpmnModel.getProcesses();
		if(processes.size()==0){
			throw new MyException("没有设计流程图!");
		}
		Process process = processes.get(0);
		//设置流程属性
        ExtendActModel extModel = actExtendDao.getModelAndBusInfo(modelId);
        String key= StringUtils.toStringByObject(extModel.getActKey());
		process.setId(key);
		process.setName(StringUtils.toStringByObject(extModel.getName()));
		process.setDocumentation(StringUtils.toStringByObject(extModel.getDescription()));
		ObjectNode objectNode = new BpmnJsonConverter().convertToJson(bpmnModel);
		//更新模型信息
		repositoryService.addModelEditorSource(modelId, objectNode.toString().getBytes("utf-8"));
		//更新模型
		model.setName(StringUtils.toStringByObject(extModel.getName()));
		model.setKey(key);
		//metaInfo
		ObjectNode modelObjectNode = objectMapper.createObjectNode();
		modelObjectNode.put(ModelDataJsonConstants.MODEL_NAME, StringUtils.toStringByObject(extModel.getName()));
		modelObjectNode.put(ModelDataJsonConstants.MODEL_REVISION, model.getVersion());
		modelObjectNode.put(ModelDataJsonConstants.MODEL_DESCRIPTION, StringUtils.toStringByObject(extModel.getDescription()));
		model.setMetaInfo(modelObjectNode.toString());
		//设置流程名称
		String deployName = process.getName();
		//转换bpmnModel为可部署的xml形式
		byte[] bpmnBytes = new BpmnXMLConverter().convertToXML(bpmnModel);
		Deployment deployment = repositoryService.createDeployment()
				.name(deployName)
				.addString(modelId + ".bpmn20.xml", new String(bpmnBytes, "utf-8"))
				.deploy();
		//更新模型部署id
		model.setDeploymentId(deployment.getId());
		repositoryService.saveModel(model);
		ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
		//与流程定义和部署对象相关的Service //创建一个流程定义查询
		List<ProcessDefinition> processDefinitionList = processEngine.getRepositoryService()
				.createProcessDefinitionQuery()
		/*指定查询条件,where条件 //使用部署对象ID查询*/
		.deploymentId(deployment.getId())
		//按照版本的升序排列
		.orderByProcessDefinitionVersion().asc()
		.list();
		if(processDefinitionList != null && processDefinitionList.size()>0){
			ProcessDefinition processDefinition =  processDefinitionList.get(0);
			//流程定义的key+版本+随机生成数
			extModel.setDefId(processDefinition.getId());
		}
		//修改扩展模型状态
        extModel.setDeploymentId(deployment.getId());
        extModel.setModelId(modelId);
		extModel.setStatus(Constants.YESNO.YES.getValue());
		extModel.setActVersion(model.getVersion());
        update(extModel);
	}

	/**
	 * 根据流程id获取流程模型和业务相关信息
	 * @param workflowId
	 * @return
	 */
	@Override
	public ExtendActModel getModelAndBusInfoByWorkflowId(String workflowId){
		ExtendActModel actModel = actExtendDao.getModelAndBusInfoByWorkflowId(workflowId);
		ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
		//与流程定义和部署对象相关的Service //创建一个流程定义查询
		List<ProcessDefinition> list = processEngine.getRepositoryService()
				.createProcessDefinitionQuery()
				/*指定查询条件,where条件*///使用部署对象ID查询
				.deploymentId(actModel.getDeploymentId())
				//.processDefinitionId(processDefinitionId)//使用流程定义ID查询
				//.processDefinitionKey(processDefinitionKey)//使用流程定义的KEY查询
				//.processDefinitionNameLike(processDefinitionNameLike)//使用流程定义的名称模糊查询

				/*排序*///按照版本的升序排列
				.orderByProcessDefinitionVersion().asc()
				//.orderByProcessDefinitionName().desc()//按照流程定义的名称降序排列

				.list();//返回一个集合列表，封装流程定义
		//.singleResult();//返回唯一结果集
		//.count();//返回结果集数量
		//.listPage(firstResult, maxResults)//分页查询
		return actExtendDao.getModelAndBusInfoByWorkflowId(workflowId);
	}

	@Override
	public ExtendActModel findByModelId(String modelId) {
		DetachedCriteria criteria = DetachedCriteria.forClass(ExtendActModel.class);
		criteria.add(Restrictions.eq("modelId",modelId));
		criteria.add(Restrictions.eq("delFlag",0));
		List<ExtendActModel> actModelList = list(criteria);
		if(actModelList != null && actModelList.size() >0){
			return actModelList.get(0);
		}
		return null;
	}
}
